﻿using System;
using System.Configuration;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.VersionControl.Server;
using CodePlex.TfsPluginSuite.Configuration;
using CodePlex.TfsPluginSuite.Helper;

namespace CodePlex.TfsPluginSuite
{
    /// <summary>
    /// Prevents users from checking in files with forbidden filename patterns. 
    /// </summary>
    public class ForbiddenPatternsPolicy : ISubscriber
    {
        public string Name
        {
            get { return "CodePlex.TfsPluginSuite.ForbiddenPatternsPolicy"; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }

        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(CheckinNotification) };
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext,
            NotificationType notificationType,
            object notificationEventArgs,
            out int statusCode,
            out string statusMessage,
            out ExceptionPropertyCollection properties)
        {
            EventNotificationStatus response = EventNotificationStatus.ActionPermitted;
            properties = new ExceptionPropertyCollection();
            statusMessage = String.Empty;
            statusCode = 0;

            var config = TfsPluginSuiteConfigurationManager.Section.ForbiddenPatternsPolicy;

            // don't run this policy if it's disabled in the config file
            if (!config.Enabled)
            {
                return response;
            }

            // If this is a check-in notification and is a decision point
            if (notificationEventArgs is CheckinNotification && notificationType == NotificationType.DecisionPoint)
            {
                CheckinNotification notification = notificationEventArgs as CheckinNotification;

                // ignore first class branches
                if (notification.CheckinType != CheckinType.Branch)
                {
                    using (var tfsHelper = new TfsHelper(requestContext, notification))
                    {
                        // iterate through all the forbidden patterns set in the config
                        foreach (ForbiddenPatternConfigurationElement forbiddenPatternConfigurationElement in config)
                        {
                            // check each of the file paths being checked in
                            // getting pendingchanges instead of using SubmittedItems from RequestContext because we need to know the changetype
                            foreach (PendingChange change in tfsHelper.GetPendingChanges())
                            {
                                var changeType = (ChangeType)change.ChangeEx;

                                //Allow deleting files that were in the system prior to this policy being put in place
                                if (!changeType.HasFlag(ChangeType.Delete))
                                {
                                    if (Regex.IsMatch(change.ServerItem, forbiddenPatternConfigurationElement.RegularExpression))
                                    {
                                        // send the user a friendly message about why this checkin is denied
                                        statusMessage = forbiddenPatternConfigurationElement.Message + System.Environment.NewLine +
                                            "First match found: " + change.ServerItem;
                                        response = EventNotificationStatus.ActionDenied;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return response;
        }
    }
}

